#include "Session.h"
#include "ThreadServer.h"
#include "../mgr/SessionMgr.h"
#include "../../../src/log/LogFactory.h"

namespace echo_service
{
	vector<shared_ptr<CTcpIoServer>> ThreadService::_tcps;
	CTcpIoSocket ThreadService::_svrSock;

	ThreadService::ThreadService()
	{
		cout << "ThreadService contract:" << endl;
		for (int i = 0; i < THREAD_NUM; ++i)
		{
			shared_ptr<CTcpIoServer> tcp(new CTcpIoServer(true));
			_tcps.push_back(tcp);
		}
	}

	ThreadService::~ThreadService()
	{
		cout << "service delete:" << endl;
	}

	void ThreadService::Start(const char* addr, DWORD port)
	{
		auto ec = _svrSock.Socket();
		CHECKERROR(ec, "init sock failed!");
		ec = LibTools::Bind(_svrSock, addr, port);
		CHECKERROR(ec, "bind failed!");
		ec = LibTools::Listen(_svrSock);
		CHECKERROR(ec, "Listen failed!");

		auto tcp = GetNextServer();
		_svrSock.SetService(tcp->GetTcpServicePtr());
		ec = _svrSock.GetService()->Init(_svrSock, true);
		CHECKERROR(ec, "init failed!");
		cout << "listen:" << *_svrSock.GetSockPtr() << ", addr:" << addr << ", port = " << port << endl;
		StartAccept(tcp);
	}

	void ThreadService::StartAccept(CTcpIoServer* server)
	{
		auto s = new Session(server);
		server->AsyncAccept(_svrSock, s->_sock, &ThreadService::HandleAccept, s);
	}

	CTcpIoServer* ThreadService::GetNextServer()
	{
		static UINT g_count = 0;
		return _tcps[g_count++%_tcps.size()].get();
	}

	DWORD ThreadService::HandleAccept(CSockError ec, void* invoker)
	{
		//static int iCount = 1;
		shared_ptr<Session> session((Session*)invoker);
		auto acceptServer = session->GetTcpServer();
		auto server = GetNextServer();
		session->SetTcpServer(server, &_svrSock);
		if (ec) {
			LOG_TOOLS(LOG_ERROR) << "HandleAccept error:" << ec.GetErrorMsg() << ", sid = " << session.get() << ", sockid = " << *session->_sock.GetSockPtr();
		}
		else
		{
			session->GetTcpServer()->Init(session->_sock);
			mgr::SessionMgr<Session>::Insert(session);
			session->Start();

			StartAccept(acceptServer);
		}
		return ec;
	}
}